#pragma once
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <vector>
#include <memory>
#include <functional>
#include <string>
#include <iostream>
#include <mutex>
#include <unordered_map>
#include <atomic>
#include <thread>
#include <queue>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "mswsock.lib")


/**
 *                                        **********************
 *                                        *     I/O端口工具类    *
 *                                        **********************
 *使用示例:
 *IOCPTool::Server server(1001); // 传入端口
 *IOCPTool::Client client;
 *
 *添加服务器
 *client.addServer("127.0.0.1",1001);
 *
 *服务器启动线程
 *std::thread serverThread([&]() {
 *  server.setOnDataReceived([&](SOCKET socket, const char* buffer, int len) {
 *      std::cout << "server received: " << buffer << std::endl;
 *      const char* message = "hellow client! server received message";
 *      server.send(socket,message);
 *  });
 *  启动服务器
 *  server.start();
 *});
 *
 *休眠3秒
 *std::this_thread::sleep_for(std::chrono::seconds(3));
 *
 *客户端启动线程
 *std::thread clientThread([&]() {
 *  client.setOnConnected([&](SOCKET socket) {
 *      std::cout << "client: connect socket = " << socket << std::endl;
 *  });
 *
 *  client.setOnDataReceived([&](SOCKET socket, const char* buffer, int len) {
 *      std::cout <<"client received message: " << buffer <<std::endl;
 *      client.send(socket,"hellow client! server received message");
 *  });
 *
 *  启动服务器
 *  client.start();
 *});
 *
 *休眠3秒
 *std::this_thread::sleep_for(std::chrono::seconds(3));
 *
 *客户端向服务器发送消息线程
 *std::thread clientSendThread([&]() {
 *  const char* buffer = "Hello World!";
 *  client.send("127.0.0.1",1001,buffer);
 *});
 *
 *serverThread.join();
 *clientThread.join();
 *clientSendThread.join();
 */


namespace IOCPTool {
    //定义常量
    constexpr int BUFFER_SIZE = 4096;


    //定义IO操作类型
    enum IO_OPERATION{
        ACCEPT,
        READ,
        WRITE
    };

    //节点类型
    enum NODE_TYPE {
        NODE,
        SERVER,
        CLIENT
    };


    class IOContextPool;

    /**
     * I/O上下文数据=============================================================================
     */
    class IOContext {
    public:

        //该I/O操作唯一标识符,相同的I/O操作，参数的地址相同，通过 GetQueuedCompletionStatus返回的 LPOVERLAPPED可反向获取 IOContext：
        OVERLAPPED m_overlapped;

        //描述数据缓冲区的信息,用于 WSARecv和 WSASend。
        WSABUF m_dataBuf;

        //I/O操作类型
        IO_OPERATION m_operation;

        //缓冲区数据
        char m_buffer[BUFFER_SIZE];

        SOCKET m_socket;

    private:
        ~IOContext(){}

        IOContext() {
            ZeroMemory(&this->m_overlapped,sizeof(OVERLAPPED));
            this->m_dataBuf.len = BUFFER_SIZE;
            this->m_dataBuf.buf = this->m_buffer;
            this->m_operation = IO_OPERATION::READ;
            this->m_socket = INVALID_SOCKET;
        }

    public:


        /**
         *
         * @param other
         * @return
         */
        bool operator == (const IOContext& other) {
            return &this->m_overlapped == &other.m_overlapped;
        }

        /**
         *
         * @param other
         * @return
         */
        bool operator != (const IOContext& other) {
            return &this->m_overlapped != &other.m_overlapped;
        }

    public:
        friend class IOContextPool;

    };

    /**
     * 上下文池=========================================================
     */
    class IOContextPool {
    private:
        int m_poolSize;

        std::mutex m_mutex;

        std::queue<IOContext*> m_unusedIOContexts;

        std::unordered_map<LPOVERLAPPED,IOContext*> m_usedIOContexts;

    private:

        /**
         *
         * @param quantity 数量
         */
        void addIOContextToPool(int quantity) {
            std::lock_guard<std::mutex> lock(this->m_mutex);
            for (int i = 0; i < quantity; i++) {
                IOContext* context = new IOContext();
                this->m_unusedIOContexts.push(context);
            }
        }



    public:

        /**
         *
         * @param size
         */
        IOContextPool(int size) {
            this->m_poolSize = size;
            this->addIOContextToPool(this->m_poolSize);
        }

        IOContextPool() {
            this->m_poolSize = 6;
            this->addIOContextToPool(this->m_poolSize);
        }

        ~IOContextPool() {
            std::lock_guard<std::mutex> lock(this->m_mutex);

            //析构m_unusedIOContexts的上下文
            while (!this->m_unusedIOContexts.empty()) {
                IOContext* context =  this->m_unusedIOContexts.front();
                this->m_unusedIOContexts.pop();
                delete context;
            }

            //m_usedIOContexts的上下文
           for (auto it = this->m_usedIOContexts.begin(); it != this->m_usedIOContexts.end(); it++) {
               IOContext* context = it->second;
               it = this->m_usedIOContexts.erase(it);
               delete context;
           }
        }

        /**
         *
         * @return
         */
        IOContext* acquireIOContext() {

            std::lock_guard<std::mutex> lock(this->m_mutex);

            //未使用IOContext队列为空则需要重新扩容，扩容数量为原来m_poolSize的一半
            if (this->m_unusedIOContexts.empty()) {

                int quantity = this->m_poolSize*0.5;
                this->addIOContextToPool(quantity);

                this->m_poolSize+= quantity;
            }

            //获取未使用IOContext
            IOContext* context = this->m_unusedIOContexts.front();
            //弹出元素
            this->m_unusedIOContexts.pop();

            //注册为已使用元素
            this->m_usedIOContexts[&context->m_overlapped] = context;

            return context;
        }


        /**
         *
         * @param lpoverlapped
         */
        void releaseContext(LPOVERLAPPED lpoverlapped) {
            std::lock_guard<std::mutex> lock(this->m_mutex);
            auto it = this->m_usedIOContexts.find(lpoverlapped);
            if (it == this->m_usedIOContexts.end())return;


            //重置数据
            ZeroMemory(&it->second->m_overlapped,sizeof(OVERLAPPED));
            it->second->m_dataBuf.len = BUFFER_SIZE;
            it->second->m_dataBuf.buf = it->second->m_buffer;
            it->second->m_operation = IO_OPERATION::READ;
            it->second->m_socket = INVALID_SOCKET;


            //重新加入未使用队列
            this->m_unusedIOContexts.push(it->second);

            //从已使用IOContexts中删除
            this->m_usedIOContexts.erase(it);
        }


        /**
         * 获取已用的上下文
         * @param lpoverlapped
         * @return
         */
        IOContext* getUsedIOContext(LPOVERLAPPED lpoverlapped) {
            std::lock_guard<std::mutex> lock(this->m_mutex);
            auto it = this->m_usedIOContexts.find(lpoverlapped);
            if (it == this->m_usedIOContexts.end()) return nullptr;

            return it->second;
        }

    };

    /**
     * 套接字控制工具，用于调用Windows扩展功能=======================================================
     */
    class WSAIoctlTool {
    private:

        //服务器接收链接函数地址
        static GUID guidAcceptEx;

        //获取接受到的链接地址的函数的地址
        static GUID guidGetAcceptExSockaddrs;

    private:

        /**
         *
         * @tparam FUNC_POINTERE
         * @param targetSocket
         * @param funcGuID
         * @param funcPointer
         * @return
         */
        template<typename FUNC_POINTERE>
        static bool WSAIoctlFun(SOCKET& targetSocket,GUID& funcGuID, FUNC_POINTERE& funcPointer) {
            DWORD bytesReceived;

            return WSAIoctl(
            targetSocket,
            SIO_GET_EXTENSION_FUNCTION_POINTER,
            &funcGuID,
            sizeof(funcGuID),
            &funcPointer,
            sizeof(funcPointer),
            &bytesReceived,
            nullptr,
            nullptr) != SOCKET_ERROR;
        }

    public:

        /**
         *异步接收套接字连接
         * @param sListenSocket 监听 socket（bind+ listen后的 socket）
         * @param sAcceptSocket 预先创建的 socket，用于接受新连接
         * @param lpOutputBuffer 接收数据的缓冲区，同时包含本地和远程地址信息
         * @param lpdwBytesReceived 返回实际接收的字节数（仅在同步操作时有效）
         * @param lpOverlapped 用于异步操作的 OVERLAPPED结构
         * @return
         */
        static bool acceptExFun(SOCKET sListenSocket,SOCKET sAcceptSocket,PVOID lpOutputBuffer, LPDWORD lpdwBytesReceived,LPOVERLAPPED lpOverlapped) {

            LPFN_ACCEPTEX lpAcceptEx = nullptr;


            if (!WSAIoctlTool::WSAIoctlFun(sListenSocket,WSAIoctlTool::guidAcceptEx,lpAcceptEx)) return false;

            return lpAcceptEx(sListenSocket,sAcceptSocket,lpOutputBuffer,0,sizeof(sockaddr_in)+16,sizeof(sockaddr_in)+16,lpdwBytesReceived,lpOverlapped) != FALSE;

        }


        /**
         *获取连接的地址
         * @param sAcceptSocket //AcceptEx的套接字
         * @param lpOutputBuffer //AcceptEx 返回的缓冲区
         * @return ip:port
         */
        static std::string GetAcceptExSockaddrsFun(SOCKET sAcceptSocket, PVOID lpOutputBuffer) {

            LPFN_GETACCEPTEXSOCKADDRS lpGetAcceptExSockaddrs = nullptr;

            //获取客户端地址信息
            sockaddr_in* localAddr = nullptr;
            sockaddr_in* remoteAddr = nullptr;
            int localAddrLen = 0;
            int remoteAddrLen = 0;

            constexpr const int addressBufferSize = sizeof(sockaddr_in) + 16;

            if (!WSAIoctlTool::WSAIoctlFun(sAcceptSocket,WSAIoctlTool::guidGetAcceptExSockaddrs,lpGetAcceptExSockaddrs)) return NULL;

            //使用使用GetAcceptExSockaddrs获取地址信息
            lpGetAcceptExSockaddrs(lpOutputBuffer,0,addressBufferSize,
            addressBufferSize,
            (sockaddr**)&localAddr,
            &localAddrLen,
            (sockaddr**)&remoteAddr,
            &remoteAddrLen);


            char clientIP[INET_ADDRSTRLEN];
            inet_ntop(AF_INET,&(remoteAddr->sin_addr),clientIP,INET_ADDRSTRLEN);
            unsigned short clientPort = ntohs(remoteAddr->sin_port);

            return std::string(clientIP,INET_ADDRSTRLEN)+":"+std::to_string(clientPort);
        }
    };

    /**
     * 节点信息=================================================================================
     */
    class NodeInformation {
    private:
        SOCKET m_socket;
        std::string m_IPPortStr;

    public:

        NodeInformation() {
            this->m_socket = INVALID_SOCKET;
            this->m_IPPortStr = "";
        }

        /**
         *
         * @param IPPortStr
         * @param socket
         */
        NodeInformation(std::string& IPPortStr, SOCKET socket) {
            this->m_socket = socket;
            this->m_IPPortStr = IPPortStr;
        }

        ~NodeInformation() {}

        /**
         *
         * @return
         */
        std::string& getIPPortStr() {
            return this->m_IPPortStr;
        }


        /**
         *
         * @return
         */
        SOCKET& getSocket() {
            return this->m_socket;
        }


        /**
         *
         * @param socket
         */
        void setSocket(SOCKET& socket) {
            this->m_socket = socket;
        }
    };


    /**
     * 远程节点数据=============================================================================
     */
    class RemoteNodesData {
    private:
        std::unordered_map<std::string, std::shared_ptr<NodeInformation>> m_remoteNodes;
        std::unordered_map<SOCKET,std::string> m_remoteNodesSocketIPPortStrMap;
        std::mutex m_remoteNodesMx;

    public:
        RemoteNodesData() {}
        ~RemoteNodesData() {}

        /**
         * 是否存在节点
         * @param socket
         * @return
         */
        bool hashNode(SOCKET& socket) {
            auto it = this->m_remoteNodesSocketIPPortStrMap.find(socket);
            return it != this->m_remoteNodesSocketIPPortStrMap.end();
        }

        /**
         * 是否存在该节点
         * @param IPPortStr
         * @return
         */
        bool hashNode(const std::string& IPPortStr) {
            auto it = this->m_remoteNodes.find(IPPortStr);
            return it != this->m_remoteNodes.end();
        }

        /**
         *
         * @param IPPortStr
         * @return
         */
        SOCKET getNodeSocketByIPPortStr(std::string& IPPortStr) {

            auto it = this->m_remoteNodes.find(IPPortStr);

            if (it == this->m_remoteNodes.end()) return INVALID_SOCKET;

            return it->second->getSocket();
        }

        /**
         *
         * @param remoteNode
         */
        void addRemoteNode(std::shared_ptr<NodeInformation>& remoteNode) {
            std::lock_guard<std::mutex> lock(this->m_remoteNodesMx);
            if (remoteNode.get() == nullptr
                || remoteNode.get()->getIPPortStr() == ""
                || remoteNode.get()->getSocket() == INVALID_SOCKET) return;

            this->m_remoteNodesSocketIPPortStrMap[remoteNode.get()->getSocket()] = remoteNode.get()->getIPPortStr();
            this->m_remoteNodes[remoteNode.get()->getIPPortStr()] = remoteNode;
        }

        /**
         * 调用此函数会清除Socket
         * @param ipPortStr
         */
        void deleteRemeoteNodesByIPPortStr(const std::string& ipPortStr) {
            std::lock_guard<std::mutex> lock(this->m_remoteNodesMx);

            if (ipPortStr == "" || ipPortStr.empty()) return;

            auto it = this->m_remoteNodes.find(ipPortStr);
            //不存在该节点数据
            if (it == this->m_remoteNodes.end()) return;

            SOCKET socket = it->second.get()->getSocket();


            this->m_remoteNodesSocketIPPortStrMap.erase(socket);
            this->m_remoteNodes.erase(it);

            //清除Socket
            closesocket(socket);
        }


        /**
         * 调用此函数会清除Socket
         * @param socket
         */
        void  deleteRemeoteNodesBySocket(SOCKET& socket) {
            std::lock_guard<std::mutex> lock(this->m_remoteNodesMx);
            if (socket == INVALID_SOCKET) return;

            auto it = this->m_remoteNodesSocketIPPortStrMap.find(socket);
            //不存在该节点数据
            if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return;

            this->m_remoteNodes.erase(it->second);
            this->m_remoteNodesSocketIPPortStrMap.erase(it);

            //清除Socket
            closesocket(socket);
        }

        /**
         * 遍历处理节点
         * @param handleFun 传入的处理函数 返回false退出循环 返回true退出循环
         */
        void traverseHandleNodes(std::function<bool(std::shared_ptr<NodeInformation>&)> handleFun) {
            std::lock_guard<std::mutex> lock(this->m_remoteNodesMx);
            for (auto& pair : this->m_remoteNodes)
                if (!handleFun(pair.second)) return;
        }


        /**
         * 清除数据
         */
        void clear() {
            this->m_remoteNodesSocketIPPortStrMap.clear();
            this->m_remoteNodes.clear();
        }
    };



    /**
    * 预备服务器信息==============================================================================
    */
    class PrePareServerInformation {
    public:
        int m_port;
        const char* m_IP;

    public:

        /**
         *
         * @param IP
         * @param port
         */
        PrePareServerInformation(const char* IP , int port) {
            this->m_port = port;
            this->m_IP = IP;
        }

        ~PrePareServerInformation(){}
    };


    /**
     * 节点接口================================================================================
     */
    class NodeInterface {
    protected:

        HANDLE m_iocpHandle;
        std::vector<std::thread> m_workerThreads;
        size_t m_maxConcurrentThreads = 1;//线程数
        std::atomic<bool> m_running;

        static std::unordered_map<NODE_TYPE,const std::string> ipPortStrMap;

        //回调函数
        std::function<void(SOCKET)> m_onConnected = NULL;
        std::function<void(SOCKET)> m_onDisconnected = NULL;
        std::function<void(SOCKET,const char*,int)> m_onDataReceived = NULL;

        //上下文池
        IOContextPool m_IOContextPool;

        //远程节点数据
        RemoteNodesData m_remoteNodesData;

        static std::mutex handleErrorMx;


    protected:

        /**
        *
        * @return
        */
        virtual NODE_TYPE getNodeType() {}


        /**
         * 跳转处理函数
         * @param context
         * @param bytesTransferred
         */
        virtual void jumpHandleFun(IOContext* context ,DWORD bytesTransferred ){}


        /**
         * 启动回调函数
         */
        virtual void startCallBackFun() {}


        /**
         * 关闭回调函数
         */
        virtual void shutDownCallBackFun() {}

        /**
         *
         * @return
         */
        const std::string& getNodeTypeStr() {
            return NodeInterface::ipPortStrMap[this->getNodeType()];
        }


        /**
       *
       * @param message
       * @param fatal
       */
        void handleError(const char* message, bool fatal = false) {

            std::lock_guard<std::mutex> lock(NodeInterface::handleErrorMx);
            DWORD error = WSAGetLastError();

            std::string str=  error == 0 ? "Unknown" : strerror( error );
            std::string logStr = this->getNodeTypeStr()+":"+message+" failed with error"+std::to_string(error)+":"+str;


            //黄色输出
           if (!fatal) {
               std::cout << "\033[33m" << logStr << "\033[0m" << std::endl;
               return;
           }

            //红色输出
            std::cout << "\033[31m" << logStr << "\033[0m" << std::endl;

            WSACleanup();
            ExitProcess(1);
        }


        /**
         *
         * @param socket
         */
        void closeSocket(SOCKET& socket) {

            if (this->m_onDisconnected != NULL) this->m_onDisconnected(socket);

            this->m_remoteNodesData.deleteRemeoteNodesBySocket(socket);
        }


        /**
         * 投递新的读操作
         * @param context
         */
        void postRead(IOContext* context) {
            DWORD flags = 0;
            DWORD bytesRead;

            context->m_operation = IO_OPERATION::READ;

            if (WSARecv(
                context->m_socket,
                &context->m_dataBuf,
                1,
                &bytesRead,
                &flags,
                &context->m_overlapped,
                NULL) != SOCKET_ERROR) return;

            DWORD error = WSAGetLastError();
            if (error == ERROR_IO_PENDING) return;
            this->handleError("WSARecv");
            this->closeSocket(context->m_socket);

        }

        /**
         * 投递新的写操作
         * @param IP
         * @param port
         * @param data
         * @param length
         */
        void postWrite(const char* IP, int port, const char* data, int length) {

            std::string IPPortStr = std::string(IP) + ":" + std::to_string(port);
            //不存在该节点
            if (!this->m_remoteNodesData.hashNode(IPPortStr)) return;

            //注册上下文
            IOContext* writeContext = this->m_IOContextPool.acquireIOContext();
            writeContext->m_socket = this->m_remoteNodesData.getNodeSocketByIPPortStr(IPPortStr);
            writeContext->m_operation = IO_OPERATION::WRITE;
            memcpy(writeContext->m_buffer,data,length);
            writeContext->m_dataBuf.len = length;

            DWORD bytesSent;
            if (WSASend(
                writeContext->m_socket,
                &writeContext->m_dataBuf,
                1,
                &bytesSent,
                0,
                &writeContext->m_overlapped,
                NULL) != SOCKET_ERROR) return;

            DWORD error = WSAGetLastError();

            if (error == WSA_IO_PENDING) return;

            this->handleError("WSASend");

            //释放上下文
            this->m_IOContextPool.releaseContext(&writeContext->m_overlapped);
            this->closeSocket(writeContext->m_socket);
        }


        /**
         *
         * @param socket
         * @param data
         * @param length
         */
        void postWrite(SOCKET socket, const char* data, int length) {

            //Socket为空
            if (socket == INVALID_SOCKET) return;

            IOContext* writeContext = this->m_IOContextPool.acquireIOContext();
            writeContext->m_socket = socket;
            writeContext->m_operation = IO_OPERATION::WRITE;
            memcpy(writeContext->m_buffer,data,length);
            writeContext->m_dataBuf.len = length;

            DWORD bytesSent;
            if (WSASend(
                writeContext->m_socket,
                &writeContext->m_dataBuf,
                1,
                &bytesSent,
                0,
                &writeContext->m_overlapped,
                NULL) != SOCKET_ERROR) return;

            DWORD error = WSAGetLastError();

            if (error == WSA_IO_PENDING) return;

            this->handleError("WSASend");

            //释放上下文
            this->m_IOContextPool.releaseContext(&writeContext->m_overlapped);
            this->closeSocket(writeContext->m_socket);
        }


        /**
         *
         * @param context
         * @param bytesTransferred
         */
        void handleRead(IOContext* context, DWORD bytesTransferred) {

            //客户端断开连接
            if (bytesTransferred == 0) {
                this->closeSocket(context->m_socket);
                return;
            }

            if (this->m_onDataReceived != NULL) {
                this->m_onDataReceived(context->m_socket,context->m_buffer,bytesTransferred);
            }


            //继续投递读操作
            this->postRead(context);
        }


        /**
         *
         * @param context
         * @param bytesTransferred
         */
        void handleWrite(IOContext* context, DWORD bytesTransferred) {
            //释放上下文回上下文池
            this->m_IOContextPool.releaseContext(&context->m_overlapped);
        }

        /**
         * 工作线程
         */
        void workerThread() {

            DWORD bytesTransferred;
            ULONG_PTR completionKey;
            LPOVERLAPPED overlapped;

            while (this->m_running) {

                BOOL result = GetQueuedCompletionStatus(this->m_iocpHandle,&bytesTransferred,&completionKey,&overlapped,INFINITE);

                //处理错误或者超时
                if (!result) {

                    DWORD error = GetLastError();

                    //超时
                    if (overlapped == NULL && error == WAIT_TIMEOUT) continue;

                    if (error != WAIT_TIMEOUT && error != ERROR_NETNAME_DELETED) this->handleError("GetQueuedCompletionStatus");


                    //客户端没有断开连接
                    if (overlapped == NULL) continue;

                    //客户端断开连接
                    IOContext* context = this->m_IOContextPool.getUsedIOContext(overlapped);

                    if (context == nullptr || context->m_operation == IO_OPERATION::ACCEPT) continue;

                    this->closeSocket(context->m_socket);

                    continue;
                }

                //收到退出信号
                if (bytesTransferred == 0 && completionKey == NULL && overlapped == NULL) break;

                //获取注册的上下文
                IOContext* context = this->m_IOContextPool.getUsedIOContext(overlapped);
                if (context == nullptr) continue;

                this->jumpHandleFun(context,bytesTransferred);

            }
        }

    public:

        void setOnConnected(std::function<void(SOCKET)> callback) {this->m_onConnected = callback;}
        void setOnDisconnected(std::function<void(SOCKET)> callback) {this->m_onDisconnected = callback;}
        void setOnDataReceived(std::function<void(SOCKET,const char* ,int)> callback){this->m_onDataReceived =callback;}

        /**
         * 启动节点
         */
        void start() {
            //已经启动
            if (this->m_running) return;

            this->startCallBackFun();

            //启动失败
            if (!this->m_running) return;


            //join线程
            for (std::thread& worker : this->m_workerThreads) worker.join();
        }

        /**
         * 关闭节点
         */
        void shutDown() {
            if (!this->m_running)  return;
            this->m_running = false;

            //关闭所有远程节点的Socket
            auto closeSocketFun = [](std::shared_ptr<NodeInformation>& remoteNode)->bool {

                if(remoteNode->getSocket() == INVALID_SOCKET) return true;
                //关闭socket
                closesocket(remoteNode.get()->getSocket());

                return true;
            }; //封装遍历处理函数

            //传入遍历处理远程节点数据函数
            this->m_remoteNodesData.traverseHandleNodes(closeSocketFun);

            //清除远程节点数据
            this->m_remoteNodesData.clear();

            //关闭IOCP句柄
            if (this->m_iocpHandle != NULL) {
                CloseHandle(this->m_iocpHandle);
                this->m_iocpHandle = NULL;
            }

            //调用节点关闭回调函数
            this->shutDownCallBackFun();

            //唤醒所有工作线程, 发送退出信号
            for (size_t i = 0; i < this->m_workerThreads.size();i++)
                PostQueuedCompletionStatus(this->m_iocpHandle,0,(ULONG_PTR)NULL,NULL);

            //等待所有工作线程
            for (std::thread& thred:this->m_workerThreads)
                if (thred.joinable()) thred.join();

            this->m_workerThreads.clear();
            WSACleanup();
        }


        /**
         *
         * @param IP
         * @param port
         * @param message
         */
        void send(const char* IP, int port, const char* message) {
            if (!this->m_running) return;

            this->postWrite(IP,port,message,strlen(message));
        }


        /**
         *
         * @param socket
         * @param message
         */
        void send(SOCKET socket, const char* message) {
            if (!this->m_running) return;
            this->postWrite(socket,message,strlen(message));
        }


        NodeInterface() {}
        virtual ~NodeInterface() {}
    };


    /**
     * 服务器==================================================================================
     */
    class Server : public NodeInterface {

    private:
        int m_port;
        SOCKET m_listenSocket;

        //static constexpr不需要类外定义
        static constexpr NODE_TYPE nodeType = IOCPTool::NODE_TYPE::SERVER;

    private:

        /**
         * 投递新的接收连接操作
         */
        void postAccept() {

            SOCKET clientSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
            if (clientSocket == INVALID_SOCKET) {
                this->handleError("WSASocket for accept");
                return;
            }

            //注册上下文
            IOContext* context = this->m_IOContextPool.acquireIOContext();
            context->m_operation = IO_OPERATION::ACCEPT;
            context->m_socket = clientSocket;

            DWORD bytesReceived;

            //接收连接
            if (WSAIoctlTool::acceptExFun(
                this->m_listenSocket,
                clientSocket,
                context->m_buffer,
                &bytesReceived,
                &context->m_overlapped)) return;

            DWORD error = WSAGetLastError();
            if (error == ERROR_IO_PENDING) return;

            this->handleError("AcceptEx");
            this->m_IOContextPool.releaseContext(&context->m_overlapped);
            closesocket(clientSocket);
        }


        /**
         * 处理接收连接
         * @param context
         */
        void handleAccept(IOContext* context) {

            //调用连接到客户端回调函数
            if (this->m_onConnected != NULL) this->m_onConnected(context->m_socket);

            //将新socket关联到IOCP
            if (CreateIoCompletionPort(
                (HANDLE)context->m_socket,
                this->m_iocpHandle,
                (ULONG_PTR)context->m_socket,
                0) == NULL) {

                this->handleError("CreateIoCompletionPort for client socket");
                closesocket(context->m_socket);
                return;
            }

            //获取客户端信息
            std::string IPPortStr = WSAIoctlTool::GetAcceptExSockaddrsFun(context->m_socket,context->m_buffer);

            //获取到的数据为空
            if (IPPortStr.empty() || IPPortStr == "") {
                this->handleError("GetAcceptExSockaddrs");
                return;
            }

            //加入远程节点数据
            std::shared_ptr<NodeInformation> nodeContextData(new NodeInformation(IPPortStr,context->m_socket));
            this->m_remoteNodesData.addRemoteNode(nodeContextData);

            //为新连接投递读操作
            this->postRead(context);


            //继续投递接收连接操作
            this->postAccept();
        }


        /**
        *
        * @param context
        * @param bytesTransferred
        */
        void jumpHandleFun(IOContext* context, DWORD bytesTransferred) override {
            switch (context->m_operation) {
                case IO_OPERATION::ACCEPT:

                    this->handleAccept(context);

                    break;

                case IO_OPERATION::READ:

                    this->handleRead(context, bytesTransferred);

                    break;

                case IO_OPERATION::WRITE:

                    this->handleWrite(context, bytesTransferred);

                    break;
            }
        }


        /**
         * 启动回调函数
         */
        void startCallBackFun() override {

            //初始化WinSocket
            WSADATA WSAData;
            if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0) {
                this->handleError("WSAStartup",true);
                return;
            }

            //创建监听socket
            this->m_listenSocket =  WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
            if (this->m_listenSocket == INVALID_SOCKET) {
                this->handleError("WSASocket",true);
                return;
            }

            //绑定地址
            sockaddr_in serverAddr;
            serverAddr.sin_family = AF_INET;
            serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
            serverAddr.sin_port = htons(this->m_port);

            if (bind(this->m_listenSocket,(sockaddr*)&serverAddr,sizeof(serverAddr)) == SOCKET_ERROR) {
                this->handleError("bind",true);
                closesocket(this->m_listenSocket);
                return;
            }

            //创建IOCP
            this->m_iocpHandle =CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
            if (this->m_iocpHandle == NULL) {
                handleError("CreateIoCompletionPort",true);
                closesocket(this->m_listenSocket);
                return;
            }

            //将监听socket关联到IOCP
            if (CreateIoCompletionPort(
                (HANDLE)this->m_listenSocket,
                this->m_iocpHandle,
                (ULONG_PTR)this->m_listenSocket,
                0) == NULL) {

                 this->handleError("CreateIoCompletionPort for listen socket",true);
                closesocket(this->m_listenSocket);
                CloseHandle(this->m_iocpHandle);
                return;
            }

            //开始监听
            if (listen(this->m_listenSocket,SOMAXCONN) == SOCKET_ERROR) {
                this->handleError("listen",true);
                closesocket(this->m_listenSocket);
                CloseHandle(this->m_iocpHandle);
                return;
            }

            //创建工作线程
            this->m_running = true;
            for (size_t i = 0; i < this->m_maxConcurrentThreads; i++)
                this->m_workerThreads.emplace_back(&IOCPTool::Server::workerThread,this);

            //投递初始化接收连接操作
            this->postAccept();
        }


        /**
         * 关闭回调函数
         */
        void shutDownCallBackFun() override {
            if (this->m_listenSocket == INVALID_SOCKET) return;
            closesocket(this->m_listenSocket);
            this->m_listenSocket = INVALID_SOCKET;
        }


    public:

        /**
         *
         * @return
         */
        NODE_TYPE getNodeType() override {
            return Server::nodeType;
        }


        /**
         *
         * @param port
         */
        Server(int port) {
            this->m_port = port;
            this->m_running = false;
        }

        ~Server() override {
            this->shutDown();
        }

    };


    /**
     * 客服端==============================================================================
     */
    class Client: public NodeInterface {

    private:
        static constexpr NODE_TYPE nodeType = NODE_TYPE::CLIENT;

        //预备服务器信息
        std::queue<PrePareServerInformation> m_prePareServers;

    private:

        /**
         *
         * @param context
         * @param bytesTransferred
         */
        void jumpHandleFun(IOContext* context, DWORD bytesTransferred) override {
            switch (context->m_operation) {
                case IO_OPERATION::READ:
                    this->handleRead(context,bytesTransferred);
                    break;
                case IO_OPERATION::WRITE:
                    this->handleWrite(context,bytesTransferred);
                    break;
                default:
                    break;
            }
        }


        /**
         *
         * @param prePareServer
         */
        void connectServer(PrePareServerInformation& prePareServer) {

            //创建Socket
            SOCKET serverSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
            if (serverSocket == INVALID_SOCKET) {
                this->handleError("WSASocket",true);
                return;
            }

            //解析服务器地址
            sockaddr_in serverAddr;
            serverAddr.sin_family = AF_INET;
            serverAddr.sin_port = htons(prePareServer.m_port);
            inet_pton(AF_INET,prePareServer.m_IP,&serverAddr.sin_addr);

            //连接服务器
            if (connect(serverSocket,(sockaddr*)&serverAddr,sizeof(serverAddr)) == SOCKET_ERROR) {
                DWORD errror = WSAGetLastError();
                this->handleError("connect");
                closesocket(serverSocket);
                return;
            }

            //将socket关联到IOCP
            if (CreateIoCompletionPort(
                (HANDLE)serverSocket,
                this->m_iocpHandle,
                (ULONG_PTR)serverSocket,
                0) == NULL) {

                this->handleError("CreateIoCompletionPort");
                closesocket(serverSocket);
                CloseHandle(this->m_iocpHandle);
                return;
            }

            this->m_running = true;

            //加入远程节点
            std::string IPPortStr = std::string(prePareServer.m_IP)+":"+std::to_string(prePareServer.m_port);
            std::shared_ptr<NodeInformation> nodeContextData(new NodeInformation(IPPortStr,serverSocket));
            this->m_remoteNodesData.addRemoteNode(nodeContextData);

            //注册上下文
            IOContext* context = this->m_IOContextPool.acquireIOContext();
            context->m_socket = serverSocket;


            //投递读操作
            this->postRead(context);

            //调用连接回调函数
            if (this->m_onConnected != NULL) this->m_onConnected(serverSocket);
        }


        /**
         * 启动回到调函数
         */
        void startCallBackFun() override {
            //初始化WinSocket
            WSAData wsaData;
            if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
                this->handleError("WSAStartup",true);
                return;
            }

            //创建IOCP
            this->m_iocpHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
            if (this->m_iocpHandle == NULL) {
                this->handleError("CreateIoCompletionPort",true);
                return;
            }

            //连接服务器
            while (!this->m_prePareServers.empty()) {
                this->connectServer(this->m_prePareServers.front());
                std::cout << "client:connectServer......."<< std::endl;
                this->m_prePareServers.pop();
            }

            // 仅当有有效连接时才创建工作线程
            if (this->m_running)
                for (size_t i = 0; i < this->m_maxConcurrentThreads ; i++)
                    this->m_workerThreads.emplace_back(&IOCPTool::Client::workerThread,this);
        }

        /**
         * 关闭回调函数
         */
        void shutDownCallBackFun() override {}

    public:
        /**
         *
         * @param IP
         * @param port
         */
        void addServer(const char* IP, int port) {
            if (this->m_running) return;
            this->m_prePareServers.push(std::move(PrePareServerInformation(IP,port)));
        }
        /**
         *
         * @return
         */
        NODE_TYPE getNodeType() override {
            return Client::nodeType;
        }


        Client() {
            this->m_running = false;
        }

        ~Client() override {
            this->shutDown();
        }
    };

};

GUID IOCPTool::WSAIoctlTool::guidAcceptEx = WSAID_ACCEPTEX;
GUID IOCPTool::WSAIoctlTool::guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;

std::unordered_map<IOCPTool::NODE_TYPE,const std::string> IOCPTool::NodeInterface::ipPortStrMap = {
    {IOCPTool::NODE_TYPE::SERVER,"server"},
    {IOCPTool::NODE_TYPE::CLIENT,"client"}
};

std::mutex IOCPTool::NodeInterface::handleErrorMx;